# -*- coding:utf-8 -*-
from bson import ObjectId

from ioservice.common.mongo import find_many_docs, find_one_doc, insert_one_model, update_one_model, \
    find_one_model, insert_models, find_many_models, delete_models, fake_delete_models_by_ids, count_documents as mongo_count_docs
from ioservice.const import *
from models.alumni import *
from utils.iterutil import generate_batch
from loguru import logger
from schemas.search import QuerySearchParam


async def get_alumni_activity_patent(alumni_id, _id, **kwargs):
    query = {"_id": ObjectId(_id), "person_id": ObjectId(alumni_id), "is_deleted": {"$ne":True}}
    res = await find_one_model(alumni_activity_patent_col, query, AlumniActivityPatentModel, **kwargs)
    return res


async def get_alumni_activity_patent_by_alumni_id(_id, context: QuerySearchParam):
    query = context.load_mongo_query(AlumniActivityPatentModel)
    query.update({"person_id": ObjectId(_id), "is_deleted":{"$ne":True}})
    total = await mongo_count_docs(alumni_activity_patent_col, query)
    res = await find_many_models(alumni_activity_patent_col, AlumniActivityPatentModel, query, sort=None, offset=context.offset, size=context.size, fields=context.fields)
    return {"total": total, "data": res}


async def insert_alumni_activity_patent(alumni_id: OID, data: AlumniActivityPatentModel):
    alumni = await find_one_doc(alumni_col, {"_id": ObjectId(alumni_id)}, projection=["_id", "person_id"])
    if not alumni:
        raise InvalidParam("alumni", f"{alumni_id} does not exists")
    res = await insert_one_model(alumni_activity_patent_col, data)
    return str(res)


async def bulk_insert_alumni_activity_patent(alumni_id, data: List[AlumniActivityPatentModel], batch_size=100):
    alumni = await find_one_doc(alumni_col, {"_id": ObjectId(alumni_id)}, projection=["_id", "person_id"])
    if not alumni:
        raise InvalidParam("alumni", f"{alumni_id} does not exists")
    for d in data:
        d.person_id = alumni_id
    results = set()
    for batch in generate_batch(data, batch_size=batch_size):
        inserted = await insert_models(alumni_activity_patent_col, batch)
        if inserted:
            results.update([str(_id) for _id in inserted])
    return results


async def bulk_update_alumni_activity_patent(alumni_id, data: List[AlumniActivityPatentModel]):
    query = {"_id": {"$in": [ObjectId(d.id) for d in data]}, "person_id": ObjectId(alumni_id)}
    res = await find_many_docs(alumni_activity_patent_col, query, projection=["_id", "person_id"])
    if not res or len(res) != len(data):
        raise InvalidParam("alumni_activity_patent",
                           f"{alumni_id} does not have {list(set([str(d.id) for d in data]) - set([str(r['_id']) for r in res]))}")
    updates = set()
    errors = []
    for d in data:
        try:
            res = await update_one_model(alumni_activity_patent_col, {"_id": ObjectId(d.id)}, d)
        except Exception as e:
            logger.error(f"update alumni_activity_patent error, {e}")
            errors.append({"id": d.id or None, "error": {e}})
        updates.add(str(d.id))
    return len(updates), errors


async def drop_alumni_activity_patent(alumni_id, ids):
    res = await find_many_docs(alumni_activity_patent_col,
                               {"_id": {"$in": [ObjectId(_id) for _id in ids]}, "person_id": ObjectId(alumni_id)},
                               projection=["_id", "person_id"])
    if not res or len(res) != len(ids):
        raise InvalidParam("alumni_activity_patent",
                           f"{alumni_id} does not have {list(set(ids) - set([str(r['_id']) for r in res]))}")
    res = await fake_delete_models_by_ids(alumni_activity_patent_col, ids)
    return res
